package pathfinding

import (
	"sync"
	"sync/atomic"

	"gddgame.cc/galaxy/common/feature/orbit"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/def"
)

//go:generate msgp

type MapMode byte

const (
	SquareMapMode MapMode = iota
	RowHexMapMode
	ColumnHexMapMode
)

func AddDirectionToSet(dirs byte, dir byte) byte {
	return dirs | (1 << dir)
}

var (
	CubeDirection = []Cube{
		Cube{1, -1, 0}, Cube{1, 0, -1}, Cube{0, 1, -1},
		Cube{-1, 1, 0}, Cube{-1, 0, 1}, Cube{0, -1, 1},
	}
	CubeDirectionMap = [][]int16{
		{-1, 4, 3},
		{5, -1, 2},
		{0, 1, -1},
	}
	ODDR = [][][]int16{{
		{0, -1}, {1, 0}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1},
	}, {
		{1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 0}, {0, -1},
	}}
	EVENR = [][][]int16{{
		{1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 0}, {0, -1},
	}, {
		{0, -1}, {1, 0}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1},
	}}
	ODDQ = [][][]int16{{
		{1, -1}, {1, 0}, {0, 1}, {-1, 0}, {-1, -1}, {0, -1},
	}, {
		{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {0, -1},
	}}
	EVENQ = [][][]int16{{
		{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {0, -1},
	}, {
		{1, -1}, {1, 0}, {0, 1}, {-1, 0}, {-1, -1}, {0, -1},
	}}
	Vector2Pool = sync.Pool{New: func() interface{} {
		return &Vector2{}
	}}
	Vector2SlicePool = sync.Pool{New: func() interface{} {
		return &Vector2Slice{}
	}}
	PathDataPool = sync.Pool{New: func() interface{} {
		return &PathData{}
	}}
	PlanDataPool = sync.Pool{New: func() interface{} {
		return &PlanData{}
	}}
	AutoDataPool = sync.Pool{New: func() interface{} {
		return &AutoData{}
	}}
	UpdateNodePool = sync.Pool{New: func() interface{} {
		return &UpdateNodeData{}
	}}
	UpdateFixedPool = sync.Pool{New: func() interface{} {
		return &UpdateFixedData{}
	}}
	MoveSeatPool = sync.Pool{New: func() interface{} {
		return &MoveSeatData{}
	}}
	GetNodePool = sync.Pool{New: func() interface{} {
		return &GetNodeData{}
	}}
	GetItemPool = sync.Pool{New: func() interface{} {
		return &GetItemData{}
	}}
	GetItemListPool = sync.Pool{New: func() interface{} {
		return &GetItemListData{}
	}}
	GetFixedListPool = sync.Pool{New: func() interface{} {
		return &GetFixedListData{}
	}}
	CanAndPreMovePool = sync.Pool{New: func() interface{} {
		return &CanAndPreMoveData{}
	}}
	CanAndPreRangePool = sync.Pool{New: func() interface{} {
		return &CanAndPreRangeData{}
	}}
	RandomPositionPool = sync.Pool{New: func() interface{} {
		return &RandomPositionData{}
	}}
	GetLinksByPool = sync.Pool{New: func() interface{} {
		return &GetLinksByData{}
	}}
	GetLinksPool = sync.Pool{New: func() interface{} {
		return &GetLinksData{}
	}}
	AddLinksPool = sync.Pool{New: func() interface{} {
		return &AddLinksData{}
	}}
	RemoveLinksPool = sync.Pool{New: func() interface{} {
		return &RemoveLinksData{}
	}}
	HasViewPool = sync.Pool{New: func() interface{} {
		return &HasViewData{}
	}}
	PositionsResponsePool = sync.Pool{New: func() interface{} {
		return &PositionsResponse{}
	}}
	TwoPositionsResponsePool = sync.Pool{New: func() interface{} {
		return &TwoPositionsResponse{}
	}}
)

//msgp:tuple Vector2
type Vector2 struct {
	X int16
	Y int16
}

func (p *Vector2) Encode() []byte {
	return orbit.EncodeLocation(int32(p.X), int32(p.Y))
}

func (p *Vector2) OddRToCube() Cube {
	var q = p.X - ((p.Y - (p.Y & 1)) / 2)
	var r = p.Y
	var s = -q - r
	return Cube{q, r, s}
}

func (p *Vector2) EvenRToCube() Cube {
	var q = p.X - (int16)((p.Y+(p.Y&1))/2)
	var r = p.Y
	var s = -q - r
	return Cube{q, r, s}
}

func (p *Vector2) OddQToCube() Cube {
	var q = p.X
	var r = p.Y - (int16)((p.X-(p.X&1))/2)
	var s = -q - r
	return Cube{q, r, s}
}

func (p *Vector2) EvenQToCube() Cube {
	var q = p.X
	var r = p.Y - (int16)((p.X+(p.X&1))/2)
	var s = -q - r
	return Cube{q, r, s}
}

func DecodeVector2(data []byte) *Vector2 {
	if data == nil {
		return nil
	}
	x, y := orbit.DecodeLocation(data)
	return &Vector2{
		X: int16(x),
		Y: int16(y),
	}
}
func GenerateVector2Slice(v *Vector2) Vector2Slice {
	return Vector2Slice{*v}
}

func DecodeVector2Slice(data [][]byte) Vector2Slice {
	v := make(Vector2Slice, len(data))
	for index, d := range data {
		v[index] = *DecodeVector2(d)
	}
	return v
}

func (p *Vector2) Equals(other *Vector2) bool {
	return p.X == other.X && p.Y == other.Y
}

func (p *Vector2) EqualsWith(x int16, y int16) bool {
	return p.X == x && p.Y == y
}

func (p *Vector2) Index(size *Vector2, point *Vector2) int16 {
	x := point.X - p.X
	y := point.Y - p.Y
	return int16(x*size.X*2 + y)
}

func (p *Vector2) Copy(point *Vector2) {
	if point == nil {
		return
	}
	p.X = point.X
	p.Y = point.Y
}

func (p *Vector2) Tailor(point *Vector2) {
	if point == nil {
		return
	}
	point.X -= p.X
	point.Y -= p.Y
}
func (p *Vector2) TailorList(nodes []Vector2) {
	if nodes == nil {
		return
	}
	for i, _ := range nodes {
		nodes[i].X -= p.X
		nodes[i].Y -= p.Y
	}
}

func (p *Vector2) Restore(point *Vector2) {
	point.X += p.X
	point.Y += p.Y
}
func (p *Vector2) RestoreList(nodes []Vector2) {
	for i, _ := range nodes {
		nodes[i].X += p.X
		nodes[i].Y += p.Y
	}
}

type Vector2Slice []Vector2

func (p Vector2Slice) Encode() [][]byte {
	d := make([][]byte, len(p))
	for i, v := range p {
		d[i] = v.Encode()
	}
	return d
}

func (p Vector2Slice) Decode(data [][]byte) {
	for _, d := range data {
		p = append(p, *DecodeVector2(d))
	}
}

//msgp:tuple NodeCost
type NodeCost struct {
	Type byte `json:"type" msg:"type"`
	Cost int  `json:"cost" msg:"cost"`
}

//msgp:tuple RegisterData
type RegisterData struct {
	Size         Vector2      `json:"size" msg:"size"`
	Center       Vector2      `json:"center" msg:"center"`
	RangeGap     int16        `json:"rangeGap" msg:"rangeGap"`
	Mode         MapMode      `json:"mode" msg:"mode"`
	Nodes        []DefineNode `json:"nodes" msg:"nodes"`
	Boundary     []Vector2    `json:"boundary" msg:"boundary"`
	NodeCostList []NodeCost   `json:"nodeCostList" msg:"nodeCostList"`
}

//msgp:tuple PathData
type PathData struct {
	Start    []byte `json:"start" msg:"start"`
	End      []byte `json:"end" msg:"end"`
	Complete bool   `json:"complete" msg:"complete"`
	Data     []byte `json:"data" msg:"data"`

	alloc int32
}

func (pathData *PathData) Marshal() ([]byte, error) {
	return pathData.MarshalMsg(nil)
}

func (pathData *PathData) Unmarshal(b []byte) error {
	_, err := pathData.UnmarshalMsg(b)
	return err
}
func (pathData *PathData) Release() {
	if pathData.alloc > 0 {
		atomic.AddInt32(&pathData.alloc, -1)
		return
	}
	pathData.alloc = 0
	PathDataPool.Put(pathData)
}

func (pathData *PathData) Alloc() {
	atomic.AddInt32(&pathData.alloc, 1)
}

func (pathData *PathData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*PathData); ok {
		pathData.Start = b.Start
		pathData.End = b.End
		pathData.Complete = b.Complete
		pathData.Data = b.Data
	}
}

//msgp:tuple PlanData
type PlanData struct {
	Start    []byte `json:"start" msg:"start"`
	End      []byte `json:"end" msg:"end"`
	Complete bool   `json:"complete" msg:"complete"`
	Data     []byte `json:"data" msg:"data"`

	alloc int32
}

func (planData *PlanData) Marshal() ([]byte, error) {
	return planData.MarshalMsg(nil)
}

func (planData *PlanData) Unmarshal(b []byte) error {
	_, err := planData.UnmarshalMsg(b)
	return err
}
func (planData *PlanData) Release() {
	if planData.alloc > 0 {
		atomic.AddInt32(&planData.alloc, -1)
		return
	}
	planData.alloc = 0
	PlanDataPool.Put(planData)
}

func (planData *PlanData) Alloc() {
	atomic.AddInt32(&planData.alloc, 1)
}

func (planData *PlanData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*PlanData); ok {
		planData.Start = b.Start
		planData.End = b.End
		planData.Complete = b.Complete
		planData.Data = b.Data
	}
}

//msgp:tuple AutoData
type AutoData struct {
	Start     []byte `json:"start" msg:"start"`
	End       []byte `json:"end" msg:"end"`
	Timestamp int64  `json:"timestamp" msg:"timestamp"`
	Data      []byte `json:"data" msg:"data"`

	alloc int32
}

func (autoData *AutoData) Marshal() ([]byte, error) {
	return autoData.MarshalMsg(nil)
}

func (autoData *AutoData) Unmarshal(b []byte) error {
	_, err := autoData.UnmarshalMsg(b)
	return err
}
func (autoData *AutoData) Release() {
	if autoData.alloc > 0 {
		atomic.AddInt32(&autoData.alloc, -1)
		return
	}
	autoData.alloc = 0
	AutoDataPool.Put(autoData)
}

func (autoData *AutoData) Alloc() {
	atomic.AddInt32(&autoData.alloc, 1)
}

func (autoData *AutoData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*AutoData); ok {
		autoData.Start = b.Start
		autoData.Timestamp = b.Timestamp
		autoData.Data = b.Data
	}
}

//msgp:tuple UpdateNodeData
type UpdateNodeData struct {
	Position []byte `json:"position" msg:"position"`
	Identity int    `json:"identity" msg:"identity"`
	T        byte   `json:"t" msg:"t"`

	alloc int32
}

func (updateNodeData *UpdateNodeData) Marshal() ([]byte, error) {
	return updateNodeData.MarshalMsg(nil)
}

func (updateNodeData *UpdateNodeData) Unmarshal(b []byte) error {
	_, err := updateNodeData.UnmarshalMsg(b)
	return err
}
func (updateNodeData *UpdateNodeData) Release() {
	if updateNodeData.alloc > 0 {
		atomic.AddInt32(&updateNodeData.alloc, -1)
		return
	}
	updateNodeData.alloc = 0
	UpdateNodePool.Put(updateNodeData)
}

func (updateNodeData *UpdateNodeData) Alloc() {
	atomic.AddInt32(&updateNodeData.alloc, 1)
}

func (updateNodeData *UpdateNodeData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*UpdateNodeData); ok {
		updateNodeData.Position = b.Position
		updateNodeData.Identity = b.Identity
		updateNodeData.T = b.T
	}
}

//msgp:tuple UpdateFixedData
type UpdateFixedData struct {
	Positions [][]byte `json:"positions" msg:"positions"`
	Identity  int      `json:"identity" msg:"identity"`
	T         byte     `json:"t" msg:"t"`
	View      byte     `json:"view" msg:"view"`
	Item      []byte   `json:"item" msg:"item"`
	Timestamp int64    `json:"timestamp" msg:"timestamp"`
	alloc     int32
}

func (updateFixedData *UpdateFixedData) Marshal() ([]byte, error) {
	return updateFixedData.MarshalMsg(nil)
}

func (updateFixedData *UpdateFixedData) Unmarshal(b []byte) error {
	_, err := updateFixedData.UnmarshalMsg(b)
	return err
}
func (updateFixedData *UpdateFixedData) Release() {
	if updateFixedData.alloc > 0 {
		atomic.AddInt32(&updateFixedData.alloc, -1)
		return
	}
	updateFixedData.alloc = 0
	UpdateFixedPool.Put(updateFixedData)
}

func (updateFixedData *UpdateFixedData) Alloc() {
	atomic.AddInt32(&updateFixedData.alloc, 1)
}

func (updateFixedData *UpdateFixedData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*UpdateFixedData); ok {
		updateFixedData.Positions = b.Positions
		updateFixedData.Identity = b.Identity
		updateFixedData.T = b.T
		updateFixedData.View = b.View
		updateFixedData.Item = b.Item
		updateFixedData.Timestamp = b.Timestamp
	}
}

//msgp:tuple MoveSeatData
type MoveSeatData struct {
	Item      []byte `json:"item" msg:"item"`
	Start     []byte `json:"start" msg:"start"`
	End       []byte `json:"end" msg:"end"`
	StartTime int64  `json:"start_time" msg:"start_time"`
	Identity  int    `json:"identity" msg:"identity"`
	View      byte   `json:"view" msg:"view"`
	Extend    []byte `json:"extend" msg:"extend"`

	alloc int32
}

func (moveSeatData *MoveSeatData) Marshal() ([]byte, error) {
	return moveSeatData.MarshalMsg(nil)
}

func (moveSeatData *MoveSeatData) Unmarshal(b []byte) error {
	_, err := moveSeatData.UnmarshalMsg(b)
	return err
}
func (moveSeatData *MoveSeatData) Release() {
	if moveSeatData.alloc > 0 {
		atomic.AddInt32(&moveSeatData.alloc, -1)
		return
	}
	moveSeatData.alloc = 0
	MoveSeatPool.Put(moveSeatData)
}

func (moveSeatData *MoveSeatData) Alloc() {
	atomic.AddInt32(&moveSeatData.alloc, 1)
}

func (moveSeatData *MoveSeatData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*MoveSeatData); ok {
		moveSeatData.Item = b.Item
		moveSeatData.Start = b.Start
		moveSeatData.End = b.End
		moveSeatData.StartTime = b.StartTime
		moveSeatData.Identity = b.Identity
		moveSeatData.View = b.View
		moveSeatData.Extend = b.Extend
	}
}

//msgp:tuple GetNodeData
type GetNodeData struct {
	Position []byte `json:"position" msg:"position"`

	alloc int32
}

func (getNodeData *GetNodeData) Marshal() ([]byte, error) {
	return getNodeData.MarshalMsg(nil)
}

func (getNodeData *GetNodeData) Unmarshal(b []byte) error {
	_, err := getNodeData.UnmarshalMsg(b)
	return err
}
func (getNodeData *GetNodeData) Release() {
	if getNodeData.alloc > 0 {
		atomic.AddInt32(&getNodeData.alloc, -1)
		return
	}
	getNodeData.alloc = 0
	GetNodePool.Put(getNodeData)
}

func (getNodeData *GetNodeData) Alloc() {
	atomic.AddInt32(&getNodeData.alloc, 1)
}

func (getNodeData *GetNodeData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*GetNodeData); ok {
		getNodeData.Position = b.Position
	}
}

//msgp:tuple GetItemData
type GetItemData struct {
	Position  []byte `json:"position" msg:"position"`
	Timestamp int64  `json:"timestamp" msg:"timestamp"`

	alloc int32
}

func (getItemData *GetItemData) Marshal() ([]byte, error) {
	return getItemData.MarshalMsg(nil)
}

func (getItemData *GetItemData) Unmarshal(b []byte) error {
	_, err := getItemData.UnmarshalMsg(b)
	return err
}
func (getItemData *GetItemData) Release() {
	if getItemData.alloc > 0 {
		atomic.AddInt32(&getItemData.alloc, -1)
		return
	}
	getItemData.alloc = 0
	GetItemPool.Put(getItemData)
}

func (getItemData *GetItemData) Alloc() {
	atomic.AddInt32(&getItemData.alloc, 1)
}

func (getItemData *GetItemData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*GetItemData); ok {
		getItemData.Position = b.Position
	}
}

//msgp:tuple GetItemListData
type GetItemListData struct {
	Positions [][]byte `json:"positions" msg:"positions"`
	Timestamp int64    `json:"timestamp" msg:"timestamp"`

	alloc int32
}

func (getItemListData *GetItemListData) Marshal() ([]byte, error) {
	return getItemListData.MarshalMsg(nil)
}

func (getItemListData *GetItemListData) Unmarshal(b []byte) error {
	_, err := getItemListData.UnmarshalMsg(b)
	return err
}
func (getItemListData *GetItemListData) Release() {
	if getItemListData.alloc > 0 {
		atomic.AddInt32(&getItemListData.alloc, -1)
		return
	}
	getItemListData.alloc = 0
	GetItemListPool.Put(getItemListData)
}

func (getItemListData *GetItemListData) Alloc() {
	atomic.AddInt32(&getItemListData.alloc, 1)
}

func (getItemListData *GetItemListData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*GetItemListData); ok {
		getItemListData.Positions = b.Positions
		getItemListData.Timestamp = b.Timestamp
	}
}

//msgp:tuple GetFixedListData
type GetFixedListData struct {
	Positions [][]byte `json:"positions" msg:"positions"`

	alloc int32
}

func (getFixedListData *GetFixedListData) Marshal() ([]byte, error) {
	return getFixedListData.MarshalMsg(nil)
}

func (getFixedListData *GetFixedListData) Unmarshal(b []byte) error {
	_, err := getFixedListData.UnmarshalMsg(b)
	return err
}
func (getFixedListData *GetFixedListData) Release() {
	if getFixedListData.alloc > 0 {
		atomic.AddInt32(&getFixedListData.alloc, -1)
		return
	}
	getFixedListData.alloc = 0
	GetFixedListPool.Put(getFixedListData)
}

func (getFixedListData *GetFixedListData) Alloc() {
	atomic.AddInt32(&getFixedListData.alloc, 1)
}

func (getFixedListData *GetFixedListData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*GetFixedListData); ok {
		getFixedListData.Positions = b.Positions
	}
}

//msgp:tuple CanAndPreMoveData
type CanAndPreMoveData struct {
	Start     []byte `json:"start" msg:"start"`
	End       []byte `json:"end" msg:"end"`
	Timestamp int64  `json:"timestamp" msg:"timestamp"`
	Data      []byte `json:"data" msg:"data"`

	alloc int32
}

func (canAndPreMoveData *CanAndPreMoveData) Marshal() ([]byte, error) {
	return canAndPreMoveData.MarshalMsg(nil)
}

func (canAndPreMoveData *CanAndPreMoveData) Unmarshal(b []byte) error {
	_, err := canAndPreMoveData.UnmarshalMsg(b)
	return err
}
func (canAndPreMoveData *CanAndPreMoveData) Release() {
	if canAndPreMoveData.alloc > 0 {
		atomic.AddInt32(&canAndPreMoveData.alloc, -1)
		return
	}
	canAndPreMoveData.alloc = 0
	CanAndPreMovePool.Put(canAndPreMoveData)
}

func (canAndPreMoveData *CanAndPreMoveData) Alloc() {
	atomic.AddInt32(&canAndPreMoveData.alloc, 1)
}

func (canAndPreMoveData *CanAndPreMoveData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*CanAndPreMoveData); ok {
		canAndPreMoveData.Start = b.Start
		canAndPreMoveData.End = b.End
		canAndPreMoveData.Timestamp = b.Timestamp
		canAndPreMoveData.Data = b.Data
	}
}

//msgp:tuple CanAndPreRangeData
type CanAndPreRangeData struct {
	Position  []byte   `json:"position" msg:"position"`
	Distance  int      `json:"distance" msg:"distance"`
	Timestamp int64    `json:"timestamp" msg:"timestamp"`
	List      [][]byte `json:"list" msg:"list"`

	alloc int32
}

func (canAndPreRangeData *CanAndPreRangeData) Marshal() ([]byte, error) {
	return canAndPreRangeData.MarshalMsg(nil)
}

func (canAndPreRangeData *CanAndPreRangeData) Unmarshal(b []byte) error {
	_, err := canAndPreRangeData.UnmarshalMsg(b)
	return err
}
func (canAndPreRangeData *CanAndPreRangeData) Release() {
	if canAndPreRangeData.alloc > 0 {
		atomic.AddInt32(&canAndPreRangeData.alloc, -1)
		return
	}
	canAndPreRangeData.alloc = 0
	CanAndPreRangePool.Put(canAndPreRangeData)
}

func (canAndPreRangeData *CanAndPreRangeData) Alloc() {
	atomic.AddInt32(&canAndPreRangeData.alloc, 1)
}

func (canAndPreRangeData *CanAndPreRangeData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*CanAndPreRangeData); ok {
		canAndPreRangeData.Position = b.Position
		canAndPreRangeData.Distance = b.Distance
		canAndPreRangeData.Timestamp = b.Timestamp
		canAndPreRangeData.List = b.List
	}
}

//msgp:tuple RandomPositionData
type RandomPositionData struct {
	CanType   int   `json:"can_type" msg:"can_type"`
	CanFix    bool  `json:"can_fix" msg:"can_fix"`
	CanSeat   bool  `json:"can_seat" msg:"can_seat"`
	Timestamp int64 `json:"timestamp" msg:"timestamp"`

	alloc int32
}

func (randomPositionData *RandomPositionData) Marshal() ([]byte, error) {
	return randomPositionData.MarshalMsg(nil)
}

func (randomPositionData *RandomPositionData) Unmarshal(b []byte) error {
	_, err := randomPositionData.UnmarshalMsg(b)
	return err
}
func (randomPositionData *RandomPositionData) Release() {
	if randomPositionData.alloc > 0 {
		atomic.AddInt32(&randomPositionData.alloc, -1)
		return
	}
	randomPositionData.alloc = 0
	RandomPositionPool.Put(randomPositionData)
}

func (randomPositionData *RandomPositionData) Alloc() {
	atomic.AddInt32(&randomPositionData.alloc, 1)
}

func (randomPositionData *RandomPositionData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*RandomPositionData); ok {
		randomPositionData.CanType = b.CanType
		randomPositionData.CanFix = b.CanFix
		randomPositionData.CanSeat = b.CanSeat
		randomPositionData.Timestamp = b.Timestamp
	}
}

//msgp:tuple GetLinksByData
type GetLinksByData struct {
	Relation byte   `json:"relation" msg:"relation"`
	Position []byte `json:"position" msg:"position"`

	alloc int32
}

func (getLinksByData *GetLinksByData) Marshal() ([]byte, error) {
	return getLinksByData.MarshalMsg(nil)
}

func (getLinksByData *GetLinksByData) Unmarshal(b []byte) error {
	_, err := getLinksByData.UnmarshalMsg(b)
	return err
}
func (getLinksByData *GetLinksByData) Release() {
	if getLinksByData.alloc > 0 {
		atomic.AddInt32(&getLinksByData.alloc, -1)
		return
	}
	getLinksByData.alloc = 0
	GetLinksByPool.Put(getLinksByData)
}

func (getLinksByData *GetLinksByData) Alloc() {
	atomic.AddInt32(&getLinksByData.alloc, 1)
}

func (getLinksByData *GetLinksByData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*GetLinksByData); ok {
		getLinksByData.Relation = b.Relation
		getLinksByData.Position = b.Position
	}
}

//msgp:tuple GetLinksData
type GetLinksData struct {
	Position []byte `json:"position" msg:"position"`

	alloc int32
}

func (getLinksData *GetLinksData) Marshal() ([]byte, error) {
	return getLinksData.MarshalMsg(nil)
}

func (getLinksData *GetLinksData) Unmarshal(b []byte) error {
	_, err := getLinksData.UnmarshalMsg(b)
	return err
}
func (getLinksData *GetLinksData) Release() {
	if getLinksData.alloc > 0 {
		atomic.AddInt32(&getLinksData.alloc, -1)
		return
	}
	getLinksData.alloc = 0
	GetLinksPool.Put(getLinksData)
}

func (getLinksData *GetLinksData) Alloc() {
	atomic.AddInt32(&getLinksData.alloc, 1)
}

func (getLinksData *GetLinksData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*GetLinksData); ok {
		getLinksData.Position = b.Position
	}
}

//msgp:tuple AddLinksData
type AddLinksData struct {
	Item      []byte   `json:"item" msg:"item"`
	Relation  byte     `json:"relation" msg:"relation"`
	Positions [][]byte `json:"positions" msg:"positions"`

	alloc int32
}

func (addLinksData *AddLinksData) Marshal() ([]byte, error) {
	return addLinksData.MarshalMsg(nil)
}

func (addLinksData *AddLinksData) Unmarshal(b []byte) error {
	_, err := addLinksData.UnmarshalMsg(b)
	return err
}
func (addLinksData *AddLinksData) Release() {
	if addLinksData.alloc > 0 {
		atomic.AddInt32(&addLinksData.alloc, -1)
		return
	}
	addLinksData.alloc = 0
	AddLinksPool.Put(addLinksData)
}

func (addLinksData *AddLinksData) Alloc() {
	atomic.AddInt32(&addLinksData.alloc, 1)
}

func (addLinksData *AddLinksData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*AddLinksData); ok {
		addLinksData.Item = b.Item
		addLinksData.Relation = b.Relation
		addLinksData.Positions = b.Positions
	}
}

//msgp:tuple RemoveLinksData
type RemoveLinksData struct {
	Item      []byte   `json:"item" msg:"item"`
	Relation  byte     `json:"relation" msg:"relation"`
	Positions [][]byte `json:"positions" msg:"positions"`

	alloc int32
}

func (removeLinksData *RemoveLinksData) Marshal() ([]byte, error) {
	return removeLinksData.MarshalMsg(nil)
}

func (removeLinksData *RemoveLinksData) Unmarshal(b []byte) error {
	_, err := removeLinksData.UnmarshalMsg(b)
	return err
}
func (removeLinksData *RemoveLinksData) Release() {
	if removeLinksData.alloc > 0 {
		atomic.AddInt32(&removeLinksData.alloc, -1)
		return
	}
	removeLinksData.alloc = 0
	RemoveLinksPool.Put(removeLinksData)
}

func (removeLinksData *RemoveLinksData) Alloc() {
	atomic.AddInt32(&removeLinksData.alloc, 1)
}

func (removeLinksData *RemoveLinksData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*RemoveLinksData); ok {
		removeLinksData.Item = b.Item
		removeLinksData.Relation = b.Relation
		removeLinksData.Positions = b.Positions
	}
}

//msgp:tuple HasViewData
type HasViewData struct {
	Start     []byte `json:"start" msg:"start"`
	Target    []byte `json:"target" msg:"target"`
	Identity  int    `json:"identity" msg:"identity"`
	Distance  int    `json:"distance" msg:"distance"`
	Timestamp int64  `json:"timestamp" msg:"timestamp"`
	Self      bool   `json:"self" msg:"self"`

	alloc int32
}

func (hasViewData *HasViewData) Marshal() ([]byte, error) {
	return hasViewData.MarshalMsg(nil)
}

func (hasViewData *HasViewData) Unmarshal(b []byte) error {
	_, err := hasViewData.UnmarshalMsg(b)
	return err
}
func (hasViewData *HasViewData) Release() {
	if hasViewData.alloc > 0 {
		atomic.AddInt32(&hasViewData.alloc, -1)
		return
	}
	hasViewData.alloc = 0
	HasViewPool.Put(hasViewData)
}

func (hasViewData *HasViewData) Alloc() {
	atomic.AddInt32(&hasViewData.alloc, 1)
}

func (hasViewData *HasViewData) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*HasViewData); ok {
		hasViewData.Start = b.Start
		hasViewData.Target = b.Target
		hasViewData.Identity = b.Identity
		hasViewData.Distance = b.Distance
		hasViewData.Timestamp = b.Timestamp
		hasViewData.Self = b.Self
	}
}

//msgp:tuple PositionsResponse
type PositionsResponse struct {
	Positions [][]byte `json:"positions" msg:"positions"`

	result Vector2Slice
	alloc  int32
}

func (positionsResponse *PositionsResponse) Marshal() ([]byte, error) {
	return positionsResponse.MarshalMsg(nil)
}

func (positionsResponse *PositionsResponse) Unmarshal(b []byte) error {
	_, err := positionsResponse.UnmarshalMsg(b)
	return err
}
func (positionsResponse *PositionsResponse) Release() {
	if positionsResponse.alloc > 0 {
		atomic.AddInt32(&positionsResponse.alloc, -1)
		return
	}
	positionsResponse.alloc = 0
	positionsResponse.result = positionsResponse.result[0:0]
	PositionsResponsePool.Put(positionsResponse)
}

func (positionsResponse *PositionsResponse) Alloc() {
	atomic.AddInt32(&positionsResponse.alloc, 1)
}

func (positionsResponse *PositionsResponse) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*PositionsResponse); ok {
		positionsResponse.Positions = b.Positions
	}
}

//msgp:tuple TwoPositionsResponse
type TwoPositionsResponse struct {
	Positions1 [][]byte `json:"positions1" msg:"positions1"`
	Positions2 [][]byte `json:"positions2" msg:"positions2"`

	result1 Vector2Slice
	result2 Vector2Slice
	alloc   int32
}

func (twoPositionsResponse *TwoPositionsResponse) Marshal() ([]byte, error) {
	return twoPositionsResponse.MarshalMsg(nil)
}

func (twoPositionsResponse *TwoPositionsResponse) Unmarshal(b []byte) error {
	_, err := twoPositionsResponse.UnmarshalMsg(b)
	return err
}
func (twoPositionsResponse *TwoPositionsResponse) Release() {
	if twoPositionsResponse.alloc > 0 {
		atomic.AddInt32(&twoPositionsResponse.alloc, -1)
		return
	}
	twoPositionsResponse.alloc = 0
	twoPositionsResponse.result1 = twoPositionsResponse.result1[0:0]
	twoPositionsResponse.result2 = twoPositionsResponse.result2[0:0]
	TwoPositionsResponsePool.Put(twoPositionsResponse)
}

func (twoPositionsResponse *TwoPositionsResponse) Alloc() {
	atomic.AddInt32(&twoPositionsResponse.alloc, 1)
}

func (twoPositionsResponse *TwoPositionsResponse) Copy(c def.OptimizeSerializer) {
	if b, ok := c.(*TwoPositionsResponse); ok {
		twoPositionsResponse.Positions1 = b.Positions1
		twoPositionsResponse.Positions2 = b.Positions2
	}
}

//msgp:tuple DefineNode
type DefineNode struct {
	Position Vector2            `json:"position" msg:"position"`
	Node     *DefineNodeContent `json:"node" msg:"node"`
}

//msgp:tuple Seat
type Seat struct {
	Item      []byte `json:"item" msg:"item"`
	StartTime int64  `json:"start_time" msg:"start_time"`
	EndTime   int64  `json:"end_time" msg:"end_time"`
	Identity  int    `json:"identity" msg:"identity"`
	View      byte   `json:"byte" msg:"view"`
	Other     *Seat  `json:"other" msg:"other"`
	Extend    []byte `json:"extend" msg:"extend"` // 包含：stop， 可预知的endTime, 下一个目标点

	InlineExtend interface{} `json:"-" msg:"-"`
}

//msgp:tuple Fixed
type Fixed struct {
	Item     []byte `json:"item" msg:"item"`
	Identity int    `json:"identity" msg:"identity"`
	Type     byte   `json:"type" msg:"type"`
	View     byte   `json:"view" msg:"view"`
}

//msgp:tuple BaseSeat
type BaseSeat struct {
	Item      []byte `json:"item" msg:"item"`
	StartTime int64  `json:"start_time" msg:"start_time"`
}

//msgp:tuple SeatMember
type SeatMember struct {
	Last *Vector2
	Next *Vector2
	Time int64
}

//msgp:tuple RelationLinkManager
type RelationLinkManager struct {
	Relation byte     `json:"relation" msg:"relation"`
	Items    [][]byte `json:"items" msg:"items"`
	mutex    sync.Mutex
}

func (manager *RelationLinkManager) InitMutex() {
	manager.mutex = sync.Mutex{}
}

//msgp RelationLinkManagerSlice
type RelationLinkManagerSlice []RelationLinkManager

//msgp:tuple DefineNodeContent
type DefineNodeContent struct {
	Type     byte `json:"type" msg:"type"`
	Identity int  `json:"identity" msg:"identity"`
	// 固定物
	Fixed *Fixed `json:"fixed" msg:"fixed"`
	// 当前存在
	Seat *Seat `json:"seat" msg:"seat"`

	LinkMap []*RelationLinkManager `json:"linkMap" msg:"linkMap"`

	IsBoundary bool `json:"isBoundary" msg:"isBoundary"`
	HasView    bool `json:"hasView" msg:"hasView"`

	// 不允许移动上去
	Lock *BaseSeat `json:"-" msg:"-"`
	// 不允许被锁定
	Pre *BaseSeat `json:"-" msg:"-"`

	mutex sync.RWMutex
}

func (content *DefineNodeContent) InitFrom(mode int, c *DefineNodeContent, m map[string]*SeatMember, position *Vector2) {
	content.Identity = c.Identity
	content.Type = c.Type
	content.Fixed = c.Fixed
	if c.Seat != nil {
		content.Seat = c.Seat
		if c.Seat.Extend != nil {
			switch mode {
			case 0:
				rr := StrategyExtendPool.Get().(*StrategyExtend)
				_, _ = rr.UnmarshalMsg(c.Seat.Extend)
				c.Seat.InlineExtend = rr
			}
		}
		m[utils.ToString(c.Seat.Item)] = &SeatMember{
			Next: position,
			Time: 0,
		}
	}
	if c.LinkMap != nil {
		content.LinkMap = c.LinkMap
		for _, v := range content.LinkMap {
			v.InitMutex()
		}
	}
	content.IsBoundary = c.IsBoundary

	content.InitMutex()
}

func (content *DefineNodeContent) MergeFrom(c *DefineNodeContent, m map[string]*SeatMember, position *Vector2) {
	if c.Identity > 0 {
		content.Identity = c.Identity
	}
	if c.IsBoundary {
		content.IsBoundary = c.IsBoundary
	}
	if c.Type > 0 {
		content.Type = c.Type
	}
	if c.Fixed != nil {
		content.Fixed = c.Fixed
	}
	if c.Seat != nil {
		if content.Seat != nil {
			delete(m, utils.ToString(content.Seat.Item))
		}
		content.Seat = c.Seat
		m[utils.ToString(c.Seat.Item)] = &SeatMember{
			Next: position,
			Time: 0,
		}
	}
}

func (content *DefineNodeContent) InitMutex() {
	content.mutex = sync.RWMutex{}
}

func (content *DefineNodeContent) Exist() bool {
	return content != nil
}

func (content *DefineNodeContent) GetIdentity() int {
	if content.Fixed != nil {
		return content.Fixed.Identity
	}
	return content.Identity
}

func (content *DefineNodeContent) GetType() byte {
	if content.Fixed != nil {
		return content.Fixed.Type
	}
	return content.Type
}

func (content *DefineNodeContent) GetItem() []byte {
	if content.Fixed != nil {
		return content.Fixed.Item
	}
	return nil
}

func (content *DefineNodeContent) GetSeat() *Seat {
	return content.Seat
}

func (content *DefineNodeContent) GetFixed() *Fixed {
	return content.Fixed
}
